using Gameplay.PVE.Config;
using Gameplay.PVE.Data;
using Gameplay.PVE.Entity;
using Gameplay.PVE.Skill;
using Gameplay.PVE.Utils;
using UnityEngine;
using Yoozoo.Managers;

namespace Gameplay.PVE
{
    public class DamageElement : ElementBase
    {
        public override void Execute()
        {
            base.Execute();
            config.element_param.TryGetValue("OutputType", out var outputType);

            if (outputType == 4)//怒气
            {
                var change = PveOutputFunction.GetOutput(config.id, source.Data, target.Data,skill.level);
                target.SetMpChange(change);
                return;
            }
            
            source.Transmit(ETransmitType.HitOthers);
            var unit = target;
            bool isBlock = false;
            //if (target is BattleUnit unit)
            {
                if (outputType == 1 || outputType == 2)//伤害
                {
                    if (source is BattleUnit battleUnit && target is BattleUnit bt)
                    {
                        bt.SetHatredSource(battleUnit);
                    }
                }
                
                float output = 0;
                /*if (outputType == 3)//治疗
                {
                    output = GetHealOutput(source.Data, target.Data);
                }
                else if (outputType == 1 || outputType == 2)
                {
                    output = -GetDamageOutput(source.Data,target.Data);
                }
                else*/
                {
                    output = (outputType == 3? 1 : -1) * PveOutputFunction.GetOutput(config.id, source.Data, target.Data,skill.level);
                    //output *= source.Data.bulletDamageRatio;
                    if (IsCrit)
                    {
                        float critical = PveGlobalVlues.criticalDamageRatio + source.Data.CriticalBonus - target.Data.CriticalReduce;
                        critical = Mathf.Clamp(critical,1f, 3f);
                        output *= critical;
                    }

                    //计算格挡
                    float blockValue = 0;
                    for (int i = 0; i < unit.Data.blockList.Count; i++)
                    {
                        if (Random.Range(0, 1f) < unit.Data.blockList[i].x && blockValue < unit.Data.blockList[i].y)
                        {
                            blockValue = unit.Data.blockList[i].y;
                        }
                    }
                    
                    
                    if (blockValue > 0)
                    {
                        PveFlyTextManager.Instance.ShowBlockFlyText(unit.Data.flyTextCriticalPosition, unit.Data.id,
                            unit.Data.team);
                        //Debug.LogError("格挡"+blockValue);
                    }

                    var ratio = GetDamageRatio(outputType, blockValue);
                    output *= ratio;

                }
                if (PveManager.Instance.isInPve && source.Data.team == 2) //挂机不显示敌方造成的伤害
                {
                    output = 0;
                }
                else
                {
                    if (outputType == 3)
                    {
                        PveFlyTextManager.Instance.ShowHealFlyText((int) Mathf.Abs(output), unit.Data.flyTextPosition,
                            source.Data.team, unit.Data.id,skill);
                    }
                    else if (target.Data.CurrentShield > 0)
                    {
                        PveFlyTextManager.Instance.ShowAbsorbFlyText(((int)Mathf.Abs(output)).ToString(),unit.Data.flyTextCriticalPosition,unit.Data.id,unit.Data.team,skill);
                    }
                    else if (outputType == 2)
                    {
                        if (source.Data.team == 2)
                        {
                            PveFlyTextManager.Instance.ShowNormalAttackFlyText(
                                -1, Mathf.Abs(output),
                                unit.Data.flyTextPosition, source.Data.team, IsCrit, unit.Data.id,skill);
                        }
                        else
                        {
                            PveFlyTextManager.Instance.ShowSkillFlyText((int) Mathf.Abs(output),
                                unit.Data.flyTextCriticalPosition, source.Data.team, IsCrit, unit.Data.id,skill);
                        }
                       
                    }
                    else
                    {
                        /*PveFlyTextManager.Instance.ShowNormalAttackFlyText(
                            this.source.Data.config.damage_merge == 1 ? this.id : -1, Mathf.Abs(output),
                            unit.Data.flyTextPosition, source.Data.team, IsCrit, unit.Data.id,skill);*/
                    }
                    /*else
                    {
                        PveFlyTextManager.Instance.ShowCriticalFlyText((int)Mathf.Abs(output),unit.Data.flyTextCriticalPosition,1,unit.Data.team == 0);
                    }*/
                }

                bool deadState = unit.Data.isDead;
                bool sourceDeadState = source.Data.isDead;
                output *= PveUtils.GlobalDamage;
                float beforeHp = unit.Data.CurrentHp;
                unit.Data.damageForward = source.Data.position - unit.Data.position;
                unit.SetHpChange(output);
                source.Data.CheckMpChange(ERecoverMpType.Attack,skill.mpSlices,source.Data.bulletDamageRatio);
                unit.Data.CheckMpChange(ERecoverMpType.Hit,skill.mpSlices,source.Data.bulletDamageRatio);

                if (source.Data.config != null && source.Data.config.energy_influence)
                {
                    //检测队友是否需要回复
                    var list = UnitManager.Instance.GetAllUnitByTeam(source.Data.team);
                    for (int i = 0; i < list.Count; i++)
                    {
                        var teammate = list[i];
                        if (teammate != source)
                        {
                            teammate.Data.CheckMpChange(ERecoverMpType.AllyAttack, skill.mpSlices,
                                source.Data.bulletDamageRatio);
                        }
                    }
                }
                
                

                //计算反伤
                if ((output < 0 || PveUtils.GlobalDamage == 0)&& unit != source)
                {
                    float thornDamage = unit.Data.Thorns * output;
                    thornDamage = Mathf.Min(thornDamage, 0);
                    if (thornDamage < 0 || (PveUtils.GlobalDamage == 0 && unit.Data.Thorns > 0))
                    {
                        PveFlyTextManager.Instance.ShowSkillFlyText((int) Mathf.Abs(thornDamage),
                            source.Data.flyTextPosition, unit.Data.team, false, source.Data.id,skill);
                        source.SetHpChange( thornDamage);
                    }
                }
                
                //计算吸血
                float afterHp = unit.Data.CurrentHp;
                if (beforeHp > afterHp)
                {
                    float blood = GetSuckBloodValue(source.Data, beforeHp - afterHp);
                    if (blood > 0)
                    {
                        int number = (int) Mathf.Abs(blood);
                        if (number > 0)
                        {
                            PveFlyTextManager.Instance.ShowHealFlyText(number, source.Data.flyTextPosition,
                                source.Data.team, source.Data.id,skill);
                        }

                        (source as BattleUnit).SetHpChange(blood, true);
                    }
                }

                BeHitByOthersArg arg = ClassManager.Get<BeHitByOthersArg>();
                arg.source = source;
                if (afterHp < beforeHp)
                {
                    unit.Transmit(ETransmitType.BeHitByOthers,arg);
                }
                
                ClassManager.Free(arg);
                if (unit.Data.isDead != deadState)
                {
                    if (unit.Data.isSummonUnit || unit is ObstacleUnit)
                    {
                        if (source.Data.summonParent != null)
                        {
                            source.Data.summonParent.Transmit(ETransmitType.Kill);
                        }
                    }
                    else
                    {
                        source.Transmit(ETransmitType.Kill);
                    }

                    float addMp = 0;
                    var mpChangeTarget = source;
                    if (unit.Data.config != null && unit.Data.config.energy_influence && unit is BattleUnit)
                    {
                        if (source.Data.summonParent != null)
                        {
                            mpChangeTarget = source.Data.summonParent;
                        }
                        if (unit.Data.isElite)
                        {
                            addMp = mpChangeTarget.Data.CheckMpChange(ERecoverMpType.KillElite);
                        }
                        else if (unit.Data.isBoss)
                        {
                            addMp = mpChangeTarget.Data.CheckMpChange(ERecoverMpType.KillBoss);
                        }
                        else
                        {
                            addMp =  mpChangeTarget.Data.CheckMpChange(ERecoverMpType.Kill);
                        }
                    }

                    if (addMp > 0)
                    {
                        PveFlyTextManager.Instance.ShowFlyTextElement(string.Format(PveUtils.GetLangText("RPG_Battle_Fly_Text_energy"),addMp),mpChangeTarget.Data.GetHudFlyTextPosition(),mpChangeTarget.Data.id,mpChangeTarget.Data.team,skill);
                    }
                }

                if (source.Data.isDead != sourceDeadState)
                {
                    if (source.Data.isSummonUnit || unit is ObstacleUnit)
                    {
                        
                    }
                    else
                    {
                        unit.Transmit(ETransmitType.Kill);
                    }
                }
            }

            IsFree = true;
        }
        private float GetSuckBloodValue(UnitData attackerData, float damage)
        {
            return attackerData.SuckBloodRatio * damage * 0.5f;
        }

        private float GetDamageRatio(int outputType,float blockValue)
        {
            float ratio = 1;
            if (outputType == 1) //普攻
            {
                ratio += source.Data.NormalAttackDamageBonus - target.Data.NormalAttackDamageReduce;
            }
            else if (outputType == 2)
            {
                ratio += source.Data.SkillDamageBonus - target.Data.SkillDamageReduce;
            }
            else
            {
                return 1;
            }

            ratio += source.Data.DamageBonus - target.Data.DamageReduce;
            ratio += source.Data.GenderDamageBonus[target.Data.Gender];
            ratio -= target.Data.GenderDamageReduce[source.Data.Gender];
            ratio -= blockValue;

            ratio = Mathf.Clamp(ratio, 0.05f, 2);
            return ratio;
        }
        
    }
}
